#include <sstream>
#include <boost/lexical_cast.hpp>
#include <boost/property_tree/json_parser.hpp>

#include "include/EventParser.h"
#include "include/CharacterCtrl.h"
#include "include/PetCtrl.h"
#include "include/SceneCtrl.h"
#include "include/Utils.h"
#include "include/Configuration.h"

using namespace std;
using namespace boost;
using namespace boost::property_tree;

EventHandler eventHandleTable[] =
{
	&CharacterCtrl::CreateRole,
	&CharacterCtrl::GetBaseInfo,
	&CharacterCtrl::GetDetailInfo,
	&PetCtrl::GetBaseInfo,
	&PetCtrl::GetDetailInfo,
	&SceneCtrl::CharacterOnline,
	&SceneCtrl::StartMove,
	&SceneCtrl::StopMove,
	&SceneCtrl::MoveScene,
};

void EventParser::ParseData(GlobalGameObj *p_game_obj)
{
	switch(p_game_obj->format)
	{
	case Common::Binary:
		break;

	case Common::Json:
		memcpy(p_game_obj->p_big_buf, p_game_obj->p_raw_data,
				p_game_obj->raw_data_len);
		p_game_obj->big_data_len = p_game_obj->raw_data_len;
		break;

	case Common::GZipJson:
	{
		if(-1 == Utils::GZDecompress(p_game_obj->p_raw_data,
			p_game_obj->raw_data_len,
			p_game_obj->p_big_buf,
			(unsigned long *)(&p_game_obj->big_data_len)))
		{
			p_game_obj->error_code = Common::DataFormatError;
			p_game_obj->error_str = "parse zlib json error";

			return;
		}
	}
		break;

	case Common::ZlibJson:
	{
		if(-1 == Utils::ZDecompress(p_game_obj->p_raw_data,
				p_game_obj->raw_data_len,
				p_game_obj->p_big_buf,
				(unsigned long *)(&p_game_obj->big_data_len)))
		{
			p_game_obj->error_code = Common::DataFormatError;
			p_game_obj->error_str = "parse zlib json error";

			return;
		}
	}
		break;

	default:
	{
		p_game_obj->error_code = Common::DataFormatError;
		p_game_obj->error_str = "unknown data format";
	}
		return;
	}

    *(p_game_obj->p_big_buf + p_game_obj->big_data_len) = 0;

#ifdef _DEBUG_LEVEL_1_
	cout << "after formatted, data content: " << endl;
	cout << p_game_obj->p_big_buf << endl;
#endif

	ParseFormattedData(p_game_obj);
	if(Common::NoError != p_game_obj->error_code)
	{
#ifdef _DEBUG_LEVEL_1_
	cout << "error after parse formatted data: " << p_game_obj->error_str << endl;
#endif
		return;
	}

	PostParseData(p_game_obj);
}

void EventParser::ParseFormattedData(GlobalGameObj *p_game_obj)
{
	stringstream stream(p_game_obj->p_big_buf);

#ifdef _DEBUG_LEVEL_1_
	cout << "EventParser packet: " << p_game_obj->p_big_buf<< endl;
#endif

	try
	{
		read_json<ptree>(stream, p_game_obj->in_tree);
	}
	catch(boost::exception &ex)
	{
		p_game_obj->error_code = Common::JsonTreeError;
		p_game_obj->error_str = "parse input json tree";

		return;
	}

	unsigned int evt;
	try
	{
		evt = p_game_obj->in_tree.get<int>("evt");
	}
	catch(boost::exception &ex)
	{
		p_game_obj->error_code = Common::EventError;
		p_game_obj->error_str = "no evt in param";

		return;
	}

	if(evt >= sizeof(eventHandleTable) / sizeof(EventHandler))
	{
		p_game_obj->error_code = Common::EventError;
		p_game_obj->error_str = lexical_cast<string>(evt);

	}

	p_game_obj->out_tree.clear();
	p_game_obj->out_tree2.clear();
	p_game_obj->out_tree3.clear();
	p_game_obj->out_format_tree.clear();
	p_game_obj->out_format_tree2.clear();
	p_game_obj->out_format_tree3.clear();

	eventHandleTable[evt](p_game_obj);

#ifdef _DEBUG_LEVEL_1_
	cout << "after eventHandleTable" << endl;
#endif
}

void EventParser::PostParseData(GlobalGameObj *p_game_obj)
{
#ifdef _DEBUG_LEVEL_1_
	cout << "enter PostParseData" << endl;
#endif
	int len = 0;
	p_game_obj->package_len = 0;
	Common::PackageHead *p_prev_package_head = NULL;
	char *p_data = (char *)p_game_obj->p_package_head;

	if(p_game_obj->out_tree.size() > 0)
	{
		if(Tree2Buf(p_game_obj->character_id, p_game_obj->format, p_game_obj->out_tree, p_game_obj->out_format_tree,
			p_data, len))
		{
			p_game_obj->error_code = Common::JsonTreeError;
			p_game_obj->error_str = "write output json tree";

			return;
		}

		p_prev_package_head = (Common::PackageHead *)p_data;

		p_data += len;
		p_game_obj->package_len += len;

#ifdef _DEBUG_LEVEL_1_
	cout << "in out_tree, package_len: " << p_game_obj->package_len  << endl;
#endif
	}

	if(p_game_obj->out_tree2.size() > 0)
	{
		if(Tree2Buf(p_game_obj->character_id, p_game_obj->format, p_game_obj->out_tree2, p_game_obj->out_format_tree2,
			p_data, len))
		{
			p_game_obj->error_code = Common::JsonTreeError;
			p_game_obj->error_str = "write output json tree2";

			return;
		}

        if(NULL != p_prev_package_head)
        {
            p_prev_package_head->multi_data = 1;
        }
		p_prev_package_head = (Common::PackageHead *)p_data;

		p_data += len;
		p_game_obj->package_len += len;
#ifdef _DEBUG_LEVEL_1_
	cout << "in out_tree2, package_len: " << p_game_obj->package_len  << endl;
#endif
	}
	if(p_game_obj->out_tree3.size() > 0)
	{
		if(Tree2Buf(p_game_obj->character_id, p_game_obj->format, p_game_obj->out_tree3, p_game_obj->out_format_tree3,
			p_data, len))
		{
			p_game_obj->error_code = Common::JsonTreeError;
			p_game_obj->error_str = "write output json tree3";

			return;
		}

		if(NULL != p_prev_package_head)
        {
            p_prev_package_head->multi_data = 1;
        }

		p_game_obj->package_len += len;
#ifdef _DEBUG_LEVEL_1_
	cout << "in out_tree3, package_len: " << p_game_obj->package_len  << endl;
#endif
	}

	// delay tree
	if(p_game_obj->out_delay_tree.size() > 0)
	{
		if(Tree2Buf(p_game_obj->character_id, p_game_obj->format, p_game_obj->out_delay_tree,
            p_game_obj->out_delay_format_tree, p_data, len))
		{
			p_game_obj->error_code = Common::JsonTreeError;
			p_game_obj->error_str = "write output json tree3";

			return;
		}

		if(NULL != p_prev_package_head)
        {
            p_prev_package_head->multi_data = 1;
        }

		p_game_obj->package_len += len;
#ifdef _DEBUG_LEVEL_1_
	cout << "in out_delay_tree, package_len: " << p_game_obj->package_len  << endl;
#endif
	}
	if(p_game_obj->out_delay_tree.size() > 0)
	{
		if(Tree2Buf(p_game_obj->character_id, p_game_obj->format, p_game_obj->out_delay_tree2,
            p_game_obj->out_delay_format_tree2, p_data, len))
		{
			p_game_obj->error_code = Common::JsonTreeError;
			p_game_obj->error_str = "write output json tree3";

			return;
		}

		if(NULL != p_prev_package_head)
        {
            p_prev_package_head->multi_data = 1;
        }

		p_game_obj->package_len += len;
#ifdef _DEBUG_LEVEL_1_
	cout << "in out_delay_tree2, package_len: " << p_game_obj->package_len  << endl;
#endif
	}
	if(p_game_obj->out_delay_tree3.size() > 0)
	{
		if(Tree2Buf(p_game_obj->character_id, p_game_obj->format, p_game_obj->out_delay_tree3,
            p_game_obj->out_delay_format_tree3, p_data, len))
		{
			p_game_obj->error_code = Common::JsonTreeError;
			p_game_obj->error_str = "write output json tree3";

			return;
		}

		if(NULL != p_prev_package_head)
        {
            p_prev_package_head->multi_data = 1;
        }

		p_game_obj->package_len += len;
#ifdef _DEBUG_LEVEL_1_
	cout << "in out_delay_tree2, package_len: " << p_game_obj->package_len  << endl;
#endif
	}
}

void EventParser::ProcessSysError(GlobalGameObj *p_game_obj)
{
	cout << "SysError: " << p_game_obj->error_code << endl <<
		"msg: " << p_game_obj->error_str << endl;

	string str = "{\"evt\":\"System_RecvError\",\"code\":";
	str = str + lexical_cast<string>(p_game_obj->error_code);
	str += ",\"msg\":\"";
	str += p_game_obj->error_str;
	str += "\"}";

	memcpy(p_game_obj->p_raw_data, str.c_str(), str.length());
	p_game_obj->raw_data_len = str.length();
	p_game_obj->p_data_head->format = Common::Json;
	p_game_obj->p_data_head->length =
		(unsigned short)(p_game_obj->raw_data_len + sizeof(int) - 1) / sizeof(int);
	p_game_obj->p_package_head->length = sizeof(struct Common::DataHead) + p_game_obj->p_data_head->length * sizeof(int);

	p_game_obj->package_len = p_game_obj->p_package_head->length + sizeof(struct Common::PackageHead);
}

int EventParser::Tree2Buf(int character_id, int format, ptree content_tree, ptree format_tree,
    char *buf, int &len)
{
    Common::PackageHead *p_package_head = PackageUtil::GetPackageHead(buf);
    FillPackageHead(p_package_head);

    int data_type;
    try
    {
        data_type = format_tree.get<int>("dataType");
    }
    catch(boost::exception &ex)
    {
        cout << "can not get data_type in Tree2Buf";
        return 1;
    }

    p_package_head->append_data = data_type;

    if(Common::EmptyData == data_type)
    {
        p_package_head->length = 0;
        return 0;
    }

    ostringstream os;

	try
	{
		write_json(os, content_tree);
	}
	catch(boost::exception &ex)
	{
	    cout << "write content_tree error in Tree2Buf";
		return 1;
	}

    Common::DataHead *p_data_head = PackageUtil::GetFirstDataHead(buf);
    p_data_head->character_id = character_id;
    p_data_head->format = format;

    char *p_data = (char *)p_data_head + sizeof(struct Common::DataHead);
    int data_len;

    switch(format)
    {
    case Common::Binary:
        return 1;

    case Common::Json:
    {
		memcpy(p_data, os.str().c_str(), os.str().length());
		data_len = os.str().length();
    }
		break;

	case Common::GZipJson:
	{
		Utils::GZCompress(os.str().c_str(), os.str().length(), p_data,
            (unsigned long *)(&data_len));
	}
		break;

	case Common::ZlibJson:
	{
		Utils::ZCompress(os.str().c_str(), os.str().length(), p_data,
            (unsigned long *)(&data_len));
	}
		break;

	default:
		break;
    }

    p_data_head->length = (data_len + 3) / 4;

    for(int i = data_len; i <= p_data_head->length * 4; i++)
    {
        *(p_data + i) = 0;
    }

    p_package_head->length = sizeof(struct Common::DataHead) + p_data_head->length * 4;

 // debug
 cout << "binary:" << endl;
 for(int i = 0; i < p_data_head->length * 4; i++)
 {
  printf("0x%02x ", *(p_data + i));
 }
 cout << endl << "binary end" << endl;
 // debug end

	switch((Common::DataType)data_type)
	{
        case Common::MulticastData:
        {
            string player_str;
            try
            {
                player_str = format_tree.get<string>("playerList");
            }
            catch(boost::exception &ex)
            {
                return 1;
            }

            vector<string> player_list;
            Utils::Str2StrList(player_str, player_list, '|');

            Common::MulticastHead *p_multi_head = PackageUtil::GetMulticastHead(buf);
            p_multi_head->player_num = player_list.size();

            int *p_player = (int *)((char *)p_multi_head + sizeof(struct Common::MulticastHead));
            for(int i = 0; i < p_multi_head->player_num; i++)
            {
                *p_player = atoi(player_list[i].c_str());
                p_player++;
            }

            p_package_head->length += sizeof(Common::MulticastHead) + p_multi_head->player_num * 4;
        }
            break;

		case Common::DelayData:
		case Common::DelayUpData:
		case Common::DelayBroadcastData:
        {
            long delay_time;
            try
            {
                delay_time = format_tree.get<long>("delayTime");
            }
            catch(boost::exception &ex)
            {
                return 1;
            }

            Common::DelayHead *p_delay_head = PackageUtil::GetDelayHead(buf);
            p_delay_head->delay_ms = delay_time;

            p_package_head->length += sizeof(struct Common::DelayHead);
        }
            break;

		case Common::DelayMulticastData:
        {
            string player_str;
            long delay_time;
            try
            {
                player_str = format_tree.get<string>("playerList");
                delay_time = format_tree.get<long>("delayTime");
            }
            catch(boost::exception &ex)
            {
                return 1;
            }

            vector<string> player_list;
            Utils::Str2StrList(player_str, player_list, '|');

            Common::MulticastHead *p_multi_head = PackageUtil::GetMulticastHead(buf);
            p_multi_head->player_num = player_list.size();

            int *p_player = (int *)((char *)p_multi_head + sizeof(struct Common::MulticastHead));
            for(int i = 0; i < p_multi_head->player_num; i++)
            {
                *p_player = atoi(player_list[i].c_str());
                p_player++;
            }

            Common::DelayHead *p_delay_head = PackageUtil::GetDelayMulticastHead(buf);
            p_delay_head->delay_ms = delay_time;

            p_package_head->length += sizeof(struct Common::DelayHead) + sizeof(struct Common::MulticastHead) + p_multi_head->player_num * 4;
        }
			break;

		default:
			break;
	}

	len = sizeof(struct Common::PackageHead) + p_package_head->length;

    return 0;
}

void EventParser::FillPackageHead(Common::PackageHead *p_package_head)
{
    p_package_head->protocol = Configuration::game.protocol;
    p_package_head->version = Configuration::game.version;
    p_package_head->game = Configuration::game.game_id;
    p_package_head->server_type = Configuration::game.server_type;
    p_package_head->server = Configuration::game.server_id;
    p_package_head->multi_data = 0;
}
